home *** CD-ROM | disk | FTP | other *** search
- /*
- * (C) Copyright 1990 Ron Burk
- * All Rights Reserved
- *
- * makehash.c - program to make hashing functions.
- *
- * Note that this is a C++ program. It has been compiled with Turbo C++
- * and Zortech C++. There is conditional code to hack around the fact that
- * Zortech does not allow a member function and a const member function of
- * the same name.
- */
-
- #ifdef __ZTC__
- #define CONST
- #else
- #define CONST const
- #endif
-
- #include <assert.h>
- #include <ctype.h>
- #include <limits.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- typedef unsigned char uchar;
- enum bool { FALSE, TRUE };
-
- FILE *OpenFile(const char *FileName, const char *IOMode)
- {
- assert(FileName != 0);
- if(IOMode == 0)
- IOMode = "r";
- FILE *FileDescriptor = fopen(FileName, IOMode);
- if(FileDescriptor == 0)
- {
- fprintf(stderr, "'%s': Can't open for mode '%s'\n",
- FileName, IOMode);
- exit(EXIT_FAILURE);
- }
- return FileDescriptor;
- }
-
- char *strdup(const char *s, size_t len)
- {
- char *ret = (char *)malloc(len+1);
- memcpy(ret, s, len);
- ret[len] = '\0';
- return ret;
- }
-
- inline char *strdup(const char *s)
- {
- return strdup(s, strlen(s));
- }
-
- class KeyWord
- {
- public:
- KeyWord(char *Name=0, char *Value=0);
- char *Name()
- { return Name_; }
- char *Value()
- { return Value_; }
- bool Read(FILE *FileDescriptor);
- private:
- char *Name_;
- char *Value_;
- };
-
- class KeyTable
- {
- public:
- KeyTable(const char *FileName);
- int NumberOfKeys()
- { return NumberOfKeys_; }
- KeyWord *operator[](int KeyWordNumber);
- void MoveTo(int Position1, int Position2);
- static const int MAXKEYWORDS;
- private:
- int NumberOfKeys_;
- KeyWord **Table;
- };
- const int KeyTable::MAXKEYWORDS = 100;
-
- class ByteTable
- {
- public:
- ByteTable();
- void SetAscending();
- void Shuffle(int Shuffles=1);
- int Index(int Value);
- uchar &operator[](int ByteNumber);
- #ifndef __ZTC__
- uchar operator[](int ByteNumber) const;
- #endif
- ByteTable &operator=(int Value);
- private:
- uchar *Table;
- };
-
- // KeyWord member functions
- KeyWord::KeyWord(char *Name__, char *Value__)
- : Name_(Name__), Value_(Value__)
- {
- }
-
- /********************************
- KeyWord::Read - read a KeyWord from an open file.
-
- Each line in the KeyWord file must be a KeyWord line, an empty line,
- or a comment. A KeyWord line is a line that contains a KeyWord
- optionally followed by white space and a value. The KeyWord and the
- value can contain any characters except white space (except the KeyWord
- cannot begin with '#'). An empty line is a line that only contains
- white space. A comment is any line that begins with a '#' (optionally
- preceeded by white space).
-
- ********************************/
-
- bool KeyWord::Read(FILE *FileDescriptor)
- {
- const int MAXLINE = 256;
- char Line[MAXLINE+1];
-
- Name_ = Value_ = 0;
- while(fgets(Line, MAXLINE, FileDescriptor))
- {
- char *Scanner = Line;
- while(*Scanner && isspace(*Scanner)) // allow leading white space
- ++Scanner;
- if(*Scanner && *Scanner != '#') // if not empty and not comment
- {
- Name_ = Scanner; // remember start of KeyWord name
- while(*Scanner && !isspace(*Scanner))
- ++Scanner; // skip over name
- if(*Scanner) // if something follows the name
- {
- *Scanner++ = '\0'; // NUL-terminate the name
- while(*Scanner && isspace(*Scanner))
- ++Scanner;
- if(*Scanner)
- {
- Value_ = Scanner; // remember start of value
- while(*Scanner && !isspace(*Scanner))
- ++Scanner;
- *Scanner = '\0';
- Value_ = strdup(Value_); // make permanent copy
- }
- }
- Name_ = strdup(Name_); // make permanent copy
- return TRUE;
- }
- }
-
- return FALSE; // hit End-Of-File
- }
-
- // KeyTable member functions
-
- KeyTable::KeyTable(const char *FileName)
- {
- Table = new KeyWord *[MAXKEYWORDS];
- assert(Table != 0);
- FILE *KeyWordFile = OpenFile(FileName, "r");
- KeyWord CurrentKeyWord;
- for(int KeyWordNumber=0; CurrentKeyWord.Read(KeyWordFile); ++KeyWordNumber)
- {
- Table[KeyWordNumber] = new KeyWord;
- *Table[KeyWordNumber] = CurrentKeyWord;
- printf( "name='%s', value='%s'\n", Table[KeyWordNumber]->Name(),
- Table[KeyWordNumber]->Value());
- }
- NumberOfKeys_ = KeyWordNumber;
- printf( "read %d keywords\n", KeyWordNumber);
- }
-
- KeyWord *KeyTable::operator[](int KeyWordNumber)
- {
- assert(KeyWordNumber >= 0);
- assert(KeyWordNumber < NumberOfKeys());
- return Table[KeyWordNumber];
- }
- void KeyTable::MoveTo(int MovePosition, int ToPosition)
- {
- KeyWord *Value = Table[MovePosition];
- int Position;
- for(Position=MovePosition; Position < NumberOfKeys()-1; ++Position)
- Table[Position] = Table[Position+1];
- for(Position=NumberOfKeys()-1; Position >= ToPosition; --Position)
- Table[Position] = Table[Position-1];
- Table[ToPosition] = Value;
- }
-
-
- // ByteTable member functions
-
- ByteTable::ByteTable()
- {
- Table = new uchar[256];
- assert(Table != 0);
- memset(Table, 0, 256);
- }
-
- void ByteTable::SetAscending()
- {
- for(int ByteNumber=0; ByteNumber < 256; ++ByteNumber)
- Table[ByteNumber] = ByteNumber;
- }
-
- void ByteTable::Shuffle(int Shuffles)
- {
- // swap each entry in the table with a randomly chosen entry
-
- for(int PassNumber=0; PassNumber < Shuffles; ++PassNumber)
- {
- for(int ByteNumber=0; ByteNumber < 256; ++ByteNumber)
- {
- int RandomPartner = rand() % 256;
- uchar OtherValue = Table[RandomPartner];
- Table[RandomPartner] = Table[ByteNumber];
- Table[ByteNumber] = OtherValue;
- }
- }
- }
-
- uchar &ByteTable::operator[](int ByteNumber)
- {
- assert(ByteNumber >= 0);
- assert(ByteNumber <= 255);
-
- return Table[ByteNumber];
- }
- #ifndef __ZTC__
- uchar ByteTable::operator[](int ByteNumber) const
- {
- assert(ByteNumber >= 0);
- assert(ByteNumber <= 255);
-
- return Table[ByteNumber];
- }
- #endif
-
- int ByteTable::Index(int Value)
- {
- uchar *Found = (uchar *)memchr(Table, Value, 256);
- if(Found)
- return Found - Table;
- else
- return -1;
- }
-
- inline
- ByteTable &ByteTable::operator=(int Value)
- {
- assert(Value >= 0);
- assert(Value <= 255);
- memset(Table, Value, 256);
- return *this;
- }
-
- int ByteHash(const char *Text, const ByteTable &HashTable)
- {
- int Hash = 0;
- while(*Text)
- Hash = HashTable[*Text++ ^ Hash];
- return Hash;
- }
-
- int MakeHash(const char *KeyWordFileName);
-
- void Usage()
- {
- fprintf(stderr, "Usage: makehash keyfile\n");
- exit(EXIT_FAILURE);
- }
-
- int main(int argc, char **argv)
- {
- if(argc < 2)
- Usage();
- char *KeyWordFileName = argv[1];
- exit(MakeHash(KeyWordFileName));
- }
-
- int MakeHash(const char *KeyWordFileName)
- {
- KeyTable InputTable(KeyWordFileName);
- int iKeyWord;
- int *Failures = new int[InputTable.NumberOfKeys()];
- assert(Failures != 0);
- ByteTable HashBytes;
- for(int Attempts=0; Attempts < 999; ++Attempts)
- {
- for(int xx=0; xx < InputTable.NumberOfKeys(); ++xx) Failures[xx]=0;
- for(int TableBase = 0; TableBase < 256; ++TableBase)
- {
- HashBytes.SetAscending(); // set equal to 0,1,2,...255
- HashBytes.Shuffle(); // randomize
- int NotEligible[256];
- for(int x=0; x < 256; ++x) NotEligible[x] = 0;
- for(int iKeyWord = 0; iKeyWord < InputTable.NumberOfKeys(); ++iKeyWord)
- {
- const char *Text = InputTable[iKeyWord]->Name();
- int TextLength = strlen(Text);
- int RandomWalk[99];
- int Hash = 0;
- uchar H[99];
- for(int i = 0; i < TextLength; ++i)
- {
- int j = Hash ^ Text[i];
- Hash = H[i] = HashBytes[j];
- ++NotEligible[j];
- RandomWalk[i] = j;
- }
- int DesiredValue = (iKeyWord + TableBase) % 256;
- for(i = TextLength-1; i >= 0; --i)
- {
- int Pos = RandomWalk[i];
- --NotEligible[Pos];
- int Other = HashBytes.Index(DesiredValue);
-
- assert(Other >= 0);
- if(NotEligible[Pos] == 0 && NotEligible[Other] == 0)
- {
- HashBytes[Other] = HashBytes[Pos];
- HashBytes[Pos] = DesiredValue;
- ++NotEligible[Other];
- ++NotEligible[Pos];
- assert(ByteHash(Text, HashBytes)
- == (iKeyWord + TableBase)%256);
- break;
- }
- else // else not eligible for swapping
- {
- DesiredValue = Other ^ Text[i];
- ++NotEligible[Other];
- }
- }
- if(i < 0)
- break;
- }
- if(iKeyWord >= InputTable.NumberOfKeys())
- {
- for(iKeyWord = 0; iKeyWord < InputTable.NumberOfKeys(); ++iKeyWord)
- {
- const char *Name = InputTable[iKeyWord]->Name();
- printf( "Hash('%s') = %d\n", Name, ByteHash(Name, HashBytes));
- }
- return EXIT_SUCCESS;
- }
- else
- {
- if(++Failures[iKeyWord] > 20)
- {
- InputTable.MoveTo(iKeyWord, 0);
- break;
- }
- }
- }
- }
-
- return EXIT_FAILURE;
- }
-